// 
// Copyright (c) 2008, Sergey Parshin (quarck@gmail.com)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice, 
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
// * Sergey Parshin name may not be used to endorse or promote products 
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS I
// NTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
// 

#ifndef __ITL_ATOMIC_H__
#define __ITL_ATOMIC_H__

#include <pthread.h>

namespace itl
{

class atomic
{
	int	m_val;

	//
	// to replace phtread_mutex with some other synchronization primitive, simple 
	// update this definition and followed 4 functions.
	//
	pthread_mutex_t m_lock;

	inline void lock() { pthread_mutex_lock(&m_lock); }

	inline void unlock()  { pthread_mutex_unlock(&m_lock); }

	inline void lock_init() { pthread_mutex_init(&m_lock, NULL); }

	inline void lock_destroy() { pthread_mutex_destroy(&m_lock); } 

public:
	inline atomic(int v)
		: m_val(v)
	{
		lock_init();
	}

	inline atomic()
		: m_val(0)
	{
		lock_init();
	}

	inline atomic(atomic &v)
		: m_val(v) // vill use operator int, to safe read value
	{
		lock_init();
	}

	inline ~atomic()
	{
		lock_destroy();
	}

	inline atomic& operator=(int v)
	{
		lock();
		m_val = v;
		unlock();
		return *this;
	}

	inline atomic& operator=(atomic &v)
	{
		int val = v; // operator int will been used
		lock();
		m_val = v;
		unlock();
		return *this;
	}

	inline operator int() 
	{
		lock();
		int val = m_val;
		unlock();
		return val;
	}

	inline bool operator==(int v) 
	{
		lock();
		bool ret = (m_val == v);
		unlock();
		return ret;
	}

	inline bool operator!=(int v) 
	{
		lock();
		bool ret = (m_val != v);
		unlock();
		return ret;
	}

	inline bool operator==(atomic &v) 
	{
		int val = v;
		return (*this == val);
	}

	inline bool operator!=(atomic &v) 
	{
		int val = v;
		return (*this != val);
	}

	inline bool operator>(int v) 
	{
		lock();
		bool ret = (m_val > v);
		unlock();
		return ret;
	}

	inline bool operator>= (int v) 
	{
		lock();
		bool ret = (m_val >= v);
		unlock();
		return ret;
	}

	inline bool operator<(int v) 
	{
		lock();
		bool ret = (m_val < v);
		unlock();
		return ret;
	}

	inline bool operator<= (int v) 
	{
		lock();
		bool ret = (m_val <= v);
		unlock();
		return ret;
	}

	inline bool operator>(atomic &v) 
	{
		int val = v;
		return (*this > val);
	}
	
	inline bool operator>=(atomic &v) 
	{
		int val = v;
		return (*this >= val);
	}

	inline bool operator<(atomic &v) 
	{
		int val = v;
		return (*this < val);
	}

	inline bool operator<=(atomic &v) 
	{
		int val = v;
		return (*this > val);
	}

	inline atomic& operator++() 
	{
		lock();
		m_val++;
		unlock();
		return *this;
	}

	inline atomic& operator--()
	{
		lock();
		m_val --;
		unlock();
		return *this;
	}

	inline atomic& operator+=(int v)
	{
		lock();
		m_val += v;
		unlock();
		return *this;
	}

	inline atomic& operator-=(int v)
	{
		lock();
		m_val -= v;
		unlock();
		return *this;
	}

	inline atomic& operator+=(atomic &v)
	{
		int val = v;
		return this->operator+=(val);
	}

	inline atomic& operator-=(atomic &v)
	{
		int val = v;
		return this->operator-=(val);
	}

	inline atomic operator+(int v) 
	{
		atomic r(*this);
		r += v;
		return r;
	}

	inline atomic operator-(int v) 
	{
		atomic r(*this);
		r -= v;
		return r;
	}

	inline atomic operator+(atomic &v) 
	{
		atomic r(*this);
		r += v;
		return r;
	}

	inline atomic operator-(atomic &v) 
	{
		atomic r(*this);
		r -= v;
		return r;
	}
};


}; // namespace itl
#endif
